import shutil
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog, simpledialog
import fitz  # PyMuPDF
import sys
import os


def resource_path(relative_path):
    """Get absolute path to resource, works for dev and for PyInstaller"""
    base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)


# os.environ["PATH"] += os.pathsep + os.path.join(
#     resource_path("D:\environment\poppler-24.07.0\Library"), "bin"
# )
poppler_path = resource_path(r"poppler")

from pdf2image import convert_from_path

# print(poppler_path)


class PDFCompressor:
    def __init__(self, root):
        self.root = root
        self.root.title("PDF压缩工具")
        # 设置窗口大小、居中
        width = 500
        height = 200
        screenwidth = root.winfo_screenwidth()
        screenheight = root.winfo_screenheight()
        geometry = "%dx%d+%d+%d" % (
            width,
            height,
            (screenwidth - width) / 2,
            (screenheight - height) / 2,
        )
        self.root.geometry(geometry)
        # 创建布局
        self.create_widgets()

    def create_widgets(self):

        # 创建并放置控件
        self.pdf_label = tk.Label(root, text="PDF文件:")
        self.pdf_label.grid(row=0, column=0)

        self.pdf_entry = tk.Entry(root, width=50)
        self.pdf_entry.grid(row=0, column=1)

        self.browse_button = tk.Button(
            root, text="文件选择", command=self.select_pdf_file
        )
        self.browse_button.grid(row=0, column=2)

        self.output_label = tk.Label(root, text="输出目录:")
        self.output_label.grid(row=1, column=0)

        self.output_entry = tk.Entry(root, width=50)
        self.output_entry.grid(row=1, column=1)

        self.output_button = tk.Button(
            root, text="目录选择", command=self.select_output_dir
        )
        self.output_button.grid(row=1, column=2)

        self.quality_label = tk.Label(root, text="图像质量 (0-100):")
        self.quality_label.place(x=5, y=70)

        self.quality_spinbox = tk.Spinbox(
            root, from_=0, to=100, width=10, textvariable=tk.StringVar(value="95")
        )
        self.quality_spinbox.place(x=120, y=70)

        self.dpi_label = tk.Label(root, text="dpi:")
        self.dpi_label.place(x=220, y=70)
        # 创建 Combobox 下拉选择框
        self.dpi_combo = ttk.Combobox(root, textvariable=tk.IntVar(), width=6)
        self.dpi_combo["values"] = ("72", "96", "108", "144", "200", "300")
        self.dpi_combo.current(1)  # 设置默认选项
        self.dpi_combo.place(x=250, y=70)

        self.compress_button = tk.Button(
            root, text="压缩PDF", command=self.compress_pdf
        )
        self.compress_button.place(x=200, y=100)

        # 进度条
        self.progress_bar = ttk.Progressbar(
            self.root, orient="horizontal", length=400, mode="determinate"
        )
        self.progress_bar.place(x=40, y=135)

        self.result_text = tk.Text(root, width=65, height=2, state=tk.DISABLED)
        self.result_text.place(x=20, y=160)
        self.update_result_text("等待压缩...")

    def select_pdf_file(self):
        """打开文件对话框选择PDF文件"""
        file_path = filedialog.askopenfilename(filetypes=[("PDF files", "*.pdf")])
        if file_path:
            self.pdf_entry.delete(0, tk.END)
            self.pdf_entry.insert(0, file_path)

    def select_output_dir(self):
        """打开文件对话框选择输出目录"""
        dir_path = filedialog.askdirectory()
        if dir_path:
            self.output_entry.delete(0, tk.END)
            self.output_entry.insert(0, dir_path)

    def compress_pdf(self):
        """压缩PDF文件"""
        # 压缩中...提示
        self.update_result_text("压缩中...")
        self.update_progress_bar(0)
        # 输入文件
        sor = self.pdf_entry.get()
        if not sor:
            self.update_result_text("压缩失败，请选择PDF文件")
            return
        # 输出文件目录
        output_dir = self.output_entry.get()
        if not output_dir:
            self.update_result_text("压缩失败，请选择输出目录")
            return
        # 图像质量quality是一个衡量和存储图像分辨率的尺度，它的范围是0到100，默认95
        quality = int(self.quality_spinbox.get())
        if not quality:
            self.update_result_text("压缩失败，请输入图像质量")
            return
        # dpi 默认情况下，pdf2image使用200 DPI作为转换的分辨率
        dpi = self.dpi_combo.get()
        if not dpi:
            self.update_result_text("压缩失败，请输入dpi")
            return
        # 源文件名
        file_name = os.path.basename(sor)
        file_name_without_ext, file_ext = os.path.splitext(file_name)
        # 输出文件
        obj = os.path.join(output_dir, f"{file_name_without_ext}_compressed.pdf")
        obj = os.path.abspath(obj)
        self.temp_dir = f"{output_dir}/.pdf_temp"
        self.doc = fitz.open(sor)
        self.totaling = self.doc.page_count
        try:
            # 转换为图片
            self.covert2pic(sor, quality, dpi)
            # 更新进度条
            self.update_progress_bar(50)
            # 图片转换为PDF
            self.pic2pdf(obj)
            self.update_progress_bar(100)
            source_size = os.path.getsize(sor) / (1024 * 1024)
            now_size = os.path.getsize(obj) / (1024 * 1024)
            self.update_result_text(
                "压缩完成！压缩前大小：{:.2f}MB，压缩后大小：{:.2f}MB\n文件保存在:{}".format(
                    source_size, now_size, str(obj)
                )
            )
        except Exception as e:
            print(e)
            self.result_text.config(text=f"压缩失败: {e}")
            # 重置进度条
            self.update_progress_bar(0)
        finally:
            if os.path.exists(self.temp_dir) and os.path.isdir(self.temp_dir):
                shutil.rmtree(self.temp_dir)

    def covert2pic(self, pdf_path, quality, dpi):
        """pdf转图片

        Args:
            pdf_path (str): PDF文件路径
            quality (int, optional): 图像质量
            dpi (int, optional): dpi
        """
        pdf_path = os.path.abspath(pdf_path)
        # 默认情况下，pdf2image使用200 dpi作为转换的分辨率，可以通过传递dpi参数来改变这个值
        images = convert_from_path(pdf_path, dpi=dpi, poppler_path=poppler_path)
        self.pic_count = len(images)
        if os.path.exists(self.temp_dir):
            os.removedirs(self.temp_dir)
        os.mkdir(self.temp_dir)
        for i, image in enumerate(images):
            lurl = f"{self.temp_dir}/p_{str(i)}.jpg"
            lurl = os.path.abspath(lurl)
            image.save(lurl, quality=quality)
            # print(lurl)
            # 更新进度条
            self.update_progress_bar(int(i) / self.pic_count * 50)
        self.doc.close()

    def pic2pdf(self, obj):
        doc = fitz.open()
        for i in range(self.pic_count):
            img = f"{self.temp_dir}/p_{str(i)}.jpg"
            img = os.path.abspath(img)
            imgdoc = fitz.open(img)
            pdfbytes = imgdoc.convert_to_pdf()
            imgpdf = fitz.open("pdf", pdfbytes)
            os.remove(img)
            doc.insert_pdf(imgpdf)
            # 更新进度条
            self.update_progress_bar(int(i) / self.pic_count * 50 + 50)
        if os.path.exists(obj):
            os.remove(obj)
        doc.save(obj)
        doc.close()

    def update_progress_bar(self, value):
        """更新进度条"""
        self.progress_bar["value"] = value
        # 更新界面
        self.root.update_idletasks()

    def update_result_text(self, text):
        """更新提示文本"""
        # 设置 Text 控件为可编辑状态
        self.result_text.config(state=tk.NORMAL)
        # 清空现有文本
        self.result_text.delete(1.0, tk.END)
        # 插入新文本
        self.result_text.insert(tk.END, text)
        # 设置 Text 控件为只读状态
        self.result_text.config(state=tk.DISABLED)
        # 更新界面
        self.root.update_idletasks()


if __name__ == "__main__":
    # 创建主窗口
    root = tk.Tk()
    app = PDFCompressor(root)
    root.mainloop()
